#include <string.h>
#include "pkt_codec.h"

#define SYNC_CODE 0x55AA
#define MAX_PACKET_SIZE 512

static uint32_t seq_counter = 0;

// CRC 计算函数，排除CRC字段
static uint16_t calc_crc(const uint8_t *data, uint16_t length)
{
    uint16_t crc = 0;
    for (size_t i = 0; i < length; ++i)
    {
        if (i != offsetof(pkt_t, crc) && i != offsetof(pkt_t, crc) + 1)
        {
            crc += data[i];
        }
    }
    return crc;
}

// 初始化编码上下文
void pkt_encode_init(codec_ctx_t *ctx, uint8_t *buffer, uint16_t buffer_size)
{
    ctx->seq = ++seq_counter;
    ctx->total_len = 0;
    ctx->crc = 0;
    ctx->buffer = buffer;
    ctx->buffer_size = buffer_size;
}

// 编码函数，支持多次编码和最终校验
bool pkt_encode(codec_ctx_t *ctx, uint16_t cmd,
                const uint8_t *input_data, uint16_t input_len, bool final_call)
{
    // 检查缓冲区是否有足够空间
    if ((ctx->total_len + input_len + sizeof(pkt_t)) > ctx->buffer_size)
    {
        return false; // 缓冲区空间不足
    }

    pkt_t *pkt = (pkt_t *)ctx->buffer;

    // 如果是第一次写入，先写入头部信息
    if (ctx->total_len == 0)
    {
        pkt->header = SYNC_CODE;
        pkt->seq = seq_counter;
        pkt->cmd = cmd;
        pkt->data_len = 0;        // 数据长度从零开始
        pkt->len = sizeof(pkt_t); // 初始设置长度为头部大小
    }

    // 写入数据部分
    memcpy(pkt->data + pkt->data_len, input_data, input_len);
    pkt->data_len += input_len;
    pkt->len += input_len;
    ctx->total_len = pkt->len;

    // 如果是最后一次调用，计算总长度和CRC
    if (final_call)
    {
        pkt->crc = calc_crc((uint8_t *)pkt, pkt->len);
    }

    return true;
}

void pkt_decode_init(decoder_ctx_t *decoder_ctx, pkt_t *pkt)
{
    decoder_ctx->state = DECODE_STATE_SYNC;
    decoder_ctx->bytes_received = 0;
    decoder_ctx->current_packet = pkt;
    decoder_ctx->expected_len = 0;
}

bool pkt_decode(decoder_ctx_t *decoder_ctx, uint8_t byte)
{
    pkt_t *pkt = decoder_ctx->current_packet;

    switch (decoder_ctx->state)
    {
        case DECODE_STATE_SYNC:
            if (decoder_ctx->bytes_received == 0 && (byte & 0xFF) == (SYNC_CODE & 0xFF))
            {
                decoder_ctx->bytes_received++;
            }
            else if (decoder_ctx->bytes_received == 1 && (byte & 0xFF) == ((SYNC_CODE >> 8) & 0xFF))
            {
                decoder_ctx->bytes_received = 0;
                decoder_ctx->state = DECODE_STATE_HEADER;
                pkt->header = SYNC_CODE;
            }
            else
            {
                decoder_ctx->bytes_received = 0; // 重新等待同步码
            }
            break;

        case DECODE_STATE_HEADER:
            ((uint8_t *)&pkt->len)[decoder_ctx->bytes_received++] = byte;
            if (decoder_ctx->bytes_received == (sizeof(pkt->len) + sizeof(pkt->crc) + sizeof(pkt->seq) + sizeof(pkt->cmd) + sizeof(pkt->data_len)))
            {
                decoder_ctx->state = DECODE_STATE_BODY;
                decoder_ctx->expected_len = pkt->len;
                decoder_ctx->bytes_received = 0;
                if (pkt->len > MAX_PACKET_SIZE)
                {
                    pkt_decode_init(decoder_ctx, pkt); // 重置状态机，数据包过大
                    return false;
                }
            }
            break;

        case DECODE_STATE_BODY:
            pkt->data[decoder_ctx->bytes_received++] = byte;
            if (decoder_ctx->bytes_received == pkt->data_len)
            {
                // 完整数据包已接收，计算CRC并验证
                uint16_t calc_crc_value = calc_crc((uint8_t *)pkt, pkt->len);
                if (calc_crc_value == pkt->crc)
                {
                    pkt_decode_init(decoder_ctx, pkt); // 解码完成，重置状态机
                    return true;                    // 数据包有效
                }
                else
                {
                    pkt_decode_init(decoder_ctx, pkt); // CRC 校验失败，重置状态机
                    return false;
                }
            }
            break;
    }

    return false;
}
